import React from 'react';
import classNames from 'classnames';

import { IControledDOMProps } from '../../utils/props';

import { Select } from '../select';
import { IOption } from '../select/DropdownList';

export interface IChainSelectOption extends IOption {
  children?: IChainSelectOption[];
}

export interface IChainSelectProps extends IControledDOMProps {
  /** 自定义className */
  className?: string;
  /** 自定义style */
  style?: React.CSSProperties;
  /** 确定级联数和标题未选时显示 */
  titles?: IOption[];
  /** 选项内容 */
  options: IChainSelectOption[];
  /** 传入则组件受控，显示传入的内容 */
  value?: IChainSelectOption[];
  /** 级联选择默认值 */
  defaultValue?: IChainSelectOption[];
  /** 下拉框是否可筛选 */
  searchable?: boolean;
  /** 选择完成后的回调 */
  onChange?: (value: IChainSelectOption[] | []) => void;
  /** 动态加载选项 */
  loadData?: (value: IChainSelectOption) => Promise<IChainSelectOption>; // 加载数据的方法
}

export interface IChainSelectState {
  /** 当前展示的每栏选项列表数组 */
  chainOptions: IChainSelectOption[][];
  /** 已选每栏的选项数组 */
  values: IChainSelectOption[];
  renderDefaultValue: boolean;
}

export class ChainSelect extends React.Component<IChainSelectProps, IChainSelectState> {
  public static defaultProps = {
    className: '',
    style: {},
    searchable: false,
    titles: [{ value: '', label: '省' }, { value: '', label: '市' }],
  };

  public static getDerivedStateFromProps(nxtProps: IChainSelectProps, prevState: IChainSelectState) {
    const { options, value, defaultValue } = nxtProps;
    const { chainOptions } = prevState;
    if (options !== chainOptions[0]) {
      return {
        chainOptions: [options, ...chainOptions.slice(1, chainOptions.length)],
      };
    }
    if (defaultValue && !value && defaultValue.length !== prevState.values.length && prevState.renderDefaultValue) {
      return {
        values: defaultValue,
        renderDefaultValue: false,
      };
    }
    if (value && value !== prevState.values) {
      return {
        values: value,
      };
    }
    return null;
  }

  constructor(props: IChainSelectProps) {
    super(props);
    this.state = {
      chainOptions: [],
      values: [],
      renderDefaultValue: true,
    };
  }

  public componentDidMount() {
    const { titles = [], options } = this.props;
    let values: IOption[] = this.getRealValues();
    this.setState({
      chainOptions: [options],
      values: values || [...titles],
    }, () => {
      this.initData();
    });
  }

  public componentDidUpdate(prevProps: IChainSelectProps, prevState: IChainSelectState) {
    if (prevState.chainOptions[0] !== this.state.chainOptions[0]) {
      this.initData();
    }
  }

  public render() {
    const { className, style, titles = [], searchable, loadData, ...domProps } = this.props;
    const { chainOptions, values } = this.state;
    /** 级联数量 */
    const depLen = titles.length;
    return (
      <div
        {...domProps as IControledDOMProps}
        className={classNames('br-chainselect', className)}
        style={style}
      >
        {new Array(depLen).fill('').map((v, i) => {
          return (
            <Select
              key={i}
              className={`br-chainselect__item br-chainselect__depth-${depLen}`}
              type={searchable ? 'search' : ''}
              options={[titles[i], ...chainOptions[i] || []]}
              value={values[i] || titles[i]}
              onChange={(option) => this.handleChange(option, i)}
            />
          );
        })}
      </div>
    );
  }

  /**
   * 初始化级联选择
   */
  public initData() {
    const { options } = this.props;
    if (!!options.length) {
      this.deepOptions(options, 0);
    }
  }

  /**
   * 动态加载选项数据
   * @param option 加载当前option项的下一级数据
   */
  public async loadData(option: IChainSelectOption) {
    const { loadData } = this.props;
    if (loadData) {
      const data = await loadData(option);
      return data.children;
    }
  }

  /**
   * 获取传入的values，对展示内容进行初始化
   */
  public getRealValues() {
    const { defaultValue = [], value = [] } = this.props;
    let values: IOption[] = [];
    if (value.length) {
      values = value;
    } else if (defaultValue.length) {
      values = defaultValue;
    }
    return [...values];
  }

  /**
   * 修改时，将选择的值回调给父组件
   * @param values 选择的级联值集合
   */
  public onChange(values: IChainSelectOption[]) {
    const { onChange } = this.props;
    const realValues: IChainSelectOption[] = values.filter((v) => !!v.value);
    if (onChange) {
      onChange(realValues);
    }
  }

  /**
   * 递归每层选项
   * @param options 当前选择框下一级选项列表
   * @param index 当前选择项的下一级深度
   */
  public async deepOptions(options: IChainSelectOption[] = [], index: number) {
    let currentValues: IOption[] = this.getRealValues();
    if (!options.length || !currentValues.length) {
      return;
    }
    const currentOption: IChainSelectOption =
      options.filter((v) => {
        return v.value === (currentValues[index] ? currentValues[index].value : '');
      })[0] || {};
    const { children = [] } = currentOption;
    await this.updateChainOptions(currentOption, index);
    this.deepOptions(children, index + 1);
  }

  /**
   * 下拉框onChange时
   * @param option 当前触发的选择框选项信息
   * @param index 当前触发的选择项的深度
   */
  public handleChange(option: IChainSelectOption, index: number) {
    let { values } = this.state;
    const hasSelected = values.some((v) => v.value === option.value);
    /** 当前值没有选择，则更新values值  */
    if (option.value !== undefined) {
      if (!hasSelected) {
        this.updateSelectedValues(option, index);
      }
      this.updateChainOptions(option, index);
    }
  }

  /**
   * 修改选择的级联选择的值
   * @param option 当前触发的选择框选项信息
   * @param index 当前触发的选择项的深度
   */
  public updateSelectedValues(option: IChainSelectOption, index: number) {
    const { titles = [] } = this.props;
    let { values } = this.state;
    const { label, value } = option;
    /** 获取当前层级，获取用titles填充的values的内容 */
    const tailTitles = titles.slice(index + 1, titles.length);
    /** 重新选级联的值，用titles的值填充values */
    values.splice(index, titles.length - index, { label, value }, ...tailTitles);
    this.setState({
      values: [...values],
    });
    this.onChange([...values]);
  }

  /**
   * 修改选择的级联选择的选项
   * @param option 当前触发的选择框选项的下一级选项信息
   * @param index 当前触发的选择项的下一级深度
   */
  public async updateChainOptions(option: IChainSelectOption, index: number) {
    const { titles = [] } = this.props;
    let { chainOptions } = this.state;
    const { children = [] } = option;
    const childIndex = index + 1;
    let childOptions: IChainSelectOption[] = children;
    /** 获取外部加载得到的option */
    if (!children.length) {
      childOptions = (await this.loadData(option)) || [];
    }
    /** chainOptions保留当前选择层级之前的选项列表数组，后面的删掉 */
    chainOptions.splice(childIndex, titles.length - childIndex);
    /** 如果当前层级数量达到定义的数量，则拼入当前项的子选项 */
    if (chainOptions.length < titles.length) {
      chainOptions = [...chainOptions, childOptions];
    }
    this.setState({
      chainOptions: [...chainOptions],
    });
  }
}
